home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 August: Tool Chest / Dev.CD Aug 00 TC Disk 2.toast / pc / sample code / human interface toolbox / colorcdef / sampctrl.p < prev   
Encoding:
Text File  |  2000-06-23  |  15.1 KB  |  495 lines

  1. {
  2.     File:        SampCtrl.p
  3.  
  4.     Contains:    This working sample defproc emulates the features of the standard button control for
  5.                 system software 7.0 on the macintosh. This defproc, while completely functional is
  6.                 intended as an explanatory example to show some of the basics of writing your own
  7.                 defproc. 
  8.                 
  9.                 Items not implemented:
  10.                 • Multiple line titles
  11.                 • Checking to be sure I am running under system 7.0
  12.     
  13.  
  14.     Written by:     
  15.  
  16.     Copyright:    Copyright © 1991-1999 by Apple Computer, Inc., All Rights Reserved.
  17.  
  18.                 You may incorporate this Apple sample source code into your program(s) without
  19.                 restriction. This Apple sample source code has been provided "AS IS" and the
  20.                 responsibility for its operation is yours. You are not permitted to redistribute
  21.                 this Apple sample source code as "Apple sample source code" after having made
  22.                 changes. If you're going to re-distribute the source, we require that you make
  23.                 it clear in the source that the code was descended from Apple sample source
  24.                 code, but that you've made changes.
  25.  
  26.     Change History (most recent first):
  27.                 7/19/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
  28.                 6/3/91        Mensch    Finished adding comments and cleaning up some bugs. could be 1.0
  29.                 5/28/91        Mensch    Created this whole thing
  30. }
  31. UNIT SampCtrl;
  32.  
  33. Interface
  34.   USES     Memory, quickdraw, Controls,Windows,GestaltEqu;
  35.   
  36. Function MySampControl(    VarCode:Integer; theControl:ControlHandle;
  37.                         Message:Integer; param:LongInt) : LongInt;
  38.                         
  39. Implementation        
  40. {     The following hack is needed because The entry for the defproc needs to be the first
  41.     executable code, and MPW places sub procedures before main procedures.}
  42.     
  43. { see tech note 256 for the discussion of the QDVarRec information here }
  44. Type    QDVarRecPtr = ^QDVarRec;
  45.         QDVarRec = Record
  46.                     randSeed:Longint;
  47.                     screenBits:Bitmap;
  48.                     arrow:cursor;
  49.                     dkGray:pattern;
  50.                     ltGray:pattern;
  51.                     gray:pattern;
  52.                     black:pattern;
  53.                     white:pattern;
  54.                     thePort:Grafptr;
  55.                    end;
  56.  
  57. Function YouMustBeJoking (a:Integer; b:ControlHandle; c:Integer; d:LongInt):LongInt;
  58.  
  59. begin
  60.     YouMustBeJoking:=MySampControl(a,b,c,d);
  61. end;
  62.  
  63. {
  64.     FUNCTION xGestalt(selector: OSType;VAR response: LONGINT): OSErr; 
  65.     Inline $202F,$0004,$A1AD,$2257,$2288,$3f40,$0008,$508F;
  66.     
  67.             Move.L Selector(sp),D0
  68.             _Gestalt
  69.             Move.L    response(sp),A1
  70.             Move.L    A0,(A1)
  71.             Move.W    D0,xGestalt(sp)
  72.             AddQ.L    #$8,sp 
  73. }
  74. Procedure GetMyQDVarRec(var a:qdVarRec);
  75. begin
  76.     a:=QDVarRecPtr(LongintPtr(SetCurrentA5)^-(SizeOf(QDVarRec)-SizeOf(qd.thePort)))^;
  77. end;
  78.  
  79. Function MySampControl(    VarCode:Integer; theControl:ControlHandle;
  80.                         Message:Integer; param:LongInt) : LongInt;
  81.                         
  82.  
  83. type    CDPInfo= packed array[0..3] of byte;
  84.  
  85. Var        
  86. { Globals used throughout the sample control go here }
  87.         theResult : Longint;        { set by individual functions/ returned by defproc }
  88.         ResultValid : Boolean;        { If true return theResult else return 0 }
  89.         
  90.         HasColorQD : Boolean;
  91.         
  92.         oldState : PenState;        { The following are for storing the state of the grafport }
  93.         oldTextMode,oldTextSize,oldTextFont : Integer;
  94.         oldClipRgn    : rgnHandle;
  95.         oldForeColor,oldBackColor : RGBColor;
  96.         
  97.         theColorTab: CCTabHandle;    { Color table to use to draw the control }
  98.         wContRGB    : RGBColor;        { the windows content color }
  99.         
  100.         { Use these to suck information from the control record for ease of use }
  101.         IsSimpleButton,isCheckBox,IsRadioBut:Boolean;
  102.         thisCDPInfo    : cdpInfo;
  103.         thisHiLite    : Integer;    { set to hilite value of the control }
  104.         thisWindow    : windowPtr;
  105.         
  106.         QD            : qdVarRec;    { our current quickdraw "globals" }
  107.         
  108.     Procedure StdDrawSetup;
  109.     { This routine preforms any standard setup that is required by the drawing functions }
  110.     
  111.     var    tempInt:integer;
  112.         tempLong:Longint;
  113.         anErr:OSErr;
  114.         aAuxWin:AuxWinHandle;
  115.         aCTab:CTabHandle;
  116.         theAuxData : AuxCtlHandle; 
  117.         FMDefSizePtr:Ptr;
  118.         SysFontSize:IntegerPtr;
  119.         
  120.     begin
  121.         GetPenState(oldState);
  122.         PenNormal;
  123.         GetMyQDVarRec(QD);
  124.         oldTextSize:=thisWindow^.txSize;
  125.         oldTextFont:=thisWindow^.txFont;
  126.         TextFont(0);                    { This is how we do it, you could set any font/size }
  127.         SysFontSize:=IntegerPtr($BA8);    { that you want }
  128.         FMDefSizePtr:=ptr($987);
  129.         if SysFontSize^<>0 then
  130.           TextSize(SysFontSize^)
  131.         else
  132.           TextSize(Integer(FMDefSizePtr^));
  133.           
  134.         HasColorQD:=false;
  135.         anErr:=Gestalt(GestaltQuickdrawVersion,tempLong);
  136.         if (anErr=0) and (tempLong>=gestalt8BitQD) then HasColorQD:=true;
  137.         if HasColorQD then 
  138.           begin
  139.             oldTextMode:=thisWindow^.txMode;
  140.             GetForeColor(oldForeColor);
  141.             GetBackColor(oldBackColor);
  142.             if GetAuxiliaryControlRecord(theControl,theAuxData) then ; {result unimportant}
  143.             theColorTab:=theAuxData^^.acCTable;
  144.             if GetAuxWin(thisWindow,aAuxWin) then ;{result unimportant}
  145.             aCTab:=aAuxWin^^.awCTable;
  146.             tempInt:=aCTab^^.ctSize;
  147.             while tempInt>=0 do
  148.               begin
  149.                 wContRGB:=aCTab^^.ctTable[tempInt].rgb;
  150.                 if aCTab^^.ctTable[tempInt].value=wContentColor then tempInt:=0;
  151.                 tempInt:=tempInt-1;
  152.               end
  153.           end;
  154.     end;
  155.     
  156.     Procedure StdDrawTearDown;
  157.     
  158.     begin
  159.         if HasColorQD then
  160.           begin
  161.             RGBForeColor(oldForeColor);
  162.             RGBBackColor(oldBackColor);
  163.             TextMode(oldTextMode);
  164.           end;
  165.         TextFont(oldTextFont);
  166.         TextSize(oldTextSize);
  167.         SetPenState(oldState);
  168.     end;
  169.     
  170.     function RoundFactor:Integer;
  171.  {this procedure calculates the rounding factor for the simple button that we are
  172.   drawing. It emulates what the standard control does }
  173.       
  174.     var        tempInt:integer;
  175.     
  176.       begin
  177.         if isSimpleButton then    {only simple buttone are rounded}
  178.           begin
  179.               tempInt:=theControl^^.ContrlRect.Bottom-theControl^^.contrlRect.Top;
  180.             RoundFactor:=tempInt div 2;
  181.           end
  182.         else RoundFactor:=0;    { check boxes and radio buttons get no rounding }
  183.     end;
  184.     
  185.     Procedure DoTestCntl;
  186.     
  187.     begin
  188.         { This routine is called in response to the testCtrl message it simply returns
  189.           the proper part code if the mouse is in the current control rect. }
  190.         if thisHiLite<255 then    { hit test is only valid if the control is enabled }
  191.           begin
  192. {preflight the part code of the result for now..}
  193.             if isCheckBox then
  194.                 theResult:=kControlCheckBoxPart
  195.             else
  196.               theResult:=kControlButtonPart;
  197.             ResultValid:=PtInRect(Point(param),TheControl^^.ContrlRect);
  198.           end;
  199.     end;
  200.     
  201.     Procedure DoCalcCRegions;
  202.     
  203.     type    patPtr=^pattern;
  204.     
  205.     var        tempInt:Integer;
  206.             thePatPtr:PatPtr;
  207.             
  208.     begin
  209.         { Called in response to all region calculation routines. This simply sets the passed
  210.           region to the bounding region of the control }
  211.         if not(isSimpleButton) then
  212.             RectRgn(rgnHandle(param),theControl^^.ContrlRect)
  213.         else
  214.           begin
  215.             GetPenState(oldState);
  216.             penNormal;
  217.             hidePen;
  218.             OpenRgn;
  219.             tempInt:=RoundFactor;
  220.             FrameRoundRect(theControl^^.ContrlRect,tempInt,tempInt);
  221.             CloseRgn(rgnHandle(param));
  222.             SetPenState(oldState);
  223.           end;
  224.  {Set the control manager pattern for control dragging. This is a good place to do this
  225.   in case it was screwed up by some other routine. This is done because we do not have our
  226.   own pos proc...}
  227.           thePatPtr:=patPtr($A34);
  228.           thePatPtr^:=QD.gray;
  229.     end;
  230.         
  231.  
  232.     procedure DoDrawIt;
  233.     
  234.     var    roundNess:Integer;
  235.         isDisabled,isHiLited,isNormal:Boolean;
  236.         tempInt:Integer;
  237.         boxWidth:Integer;
  238.         lineHeight:Integer;
  239.         textRect,ctlRect,outerRect:Rect;
  240.         theInfo:FontInfo;
  241.         useGrayText:Boolean;
  242.         aColor:RGBColor;
  243.         
  244.         {Called in response to the DrawCtrl message, this code draws the control in its proper
  245.          state in its proper colors (as defined in the controls color table. the values in the
  246.          table below refer to the control color table value type).
  247.          The proper colors for color controls are as follows (radio & checkboxes are the same):
  248.          
  249.          type/State:        Frame            Text        Background
  250.          CheckBox/normal    cFrameColor        cTextColor    window content color
  251.          CheckBox/Hilited    cFrameColor        cTextColor    window content color
  252.          CheckBox/Disabled    cFrameColor        cTextColor    window content color
  253.          SimpleBut/normal    cFrameColor        cTextColor    cBodyColor
  254.          SimpleBut/HiLited    cFrameColor        cBodyColor    cTextColor
  255.          SimpleBut/Disabled    cFrameColor        cTextColor    cBodyColor
  256.          
  257.          For disabled items, if drawing into a cGrafport then textmode is set to GrayishTextOr,
  258.          otherwise we use the old style overstrike with gray pattern in mode BIC.}
  259.          
  260.          
  261.         procedure GetCtlColor(theValue:integer; VAR theRGB:RGBColor);
  262.         
  263.         var    anInt:integer;
  264.         
  265.         begin
  266.             {Given theValue as the part code to get the color for, this routine returns its
  267.              RGB value. If no color is assigned to the part code, the first color entry is
  268.              returned. This technique can also be used to look up values in window color tables}
  269.             
  270.             anInt:=theColorTab^^.ctSize;
  271.             while anInt>=0 do
  272.               begin
  273.                 theRGB:=theColorTab^^.ctTable[anInt].rgb;
  274.                 if theColorTab^^.ctTable[anInt].value=theValue then anInt:=0;
  275.                 anInt:=anInt-1;
  276.               end
  277.         end;
  278.         
  279.           procedure CalcBackColor;
  280.         
  281.         begin
  282.             {based on the state/status of the control, set the background}
  283.             aColor:=wContRGB;        { Background color for radio/check boxes }
  284.             if isSimpleButton then
  285.               begin
  286.                 if isHiLited then GetCtlColor(cTextColor,aColor)
  287.                 else GetCtlColor(cBodyColor,aColor);
  288.               end;
  289.             If hasColorQD then RGBBackColor(aColor);
  290.         end;
  291.         
  292.           procedure CalcForeColor;
  293.         
  294.         begin
  295.             {based on the state/status of the control, set the foreground}
  296.             if (isHiLited and  isSimpleButton) then GetCtlColor(cBodyColor,aColor)
  297.             else GetCtlColor(cTextColor,aColor);
  298.             If hasColorQD then RGBForeColor(aColor);
  299.         end;
  300.         
  301.         procedure CalcFrameColor;
  302.         
  303.         begin
  304.             {based on the state/status of the control, set the frame(foreground)}
  305.             GetCtlColor(cFrameColor,aColor);
  306.             If hasColorQD then RGBForeColor(aColor);
  307.         end;
  308.         
  309.         procedure CalcTextColor;
  310.         
  311.         begin
  312.             { Set the useGrayText variable if we are ising color quickdraw and the control
  313.               owner is a cGrafPort thisWindow^.PortBits.rowBytes is also thisWindow^.portVersion}
  314.             useGrayText:=false;
  315.             if HasColorQD then
  316.               begin
  317.                 useGrayText:=(BAND(thisWindow^.PortBits.rowBytes,$C000)<>0);
  318.                 if useGrayText and isDisabled then TextMode(GrayishTextOr);
  319.                 CalcForeColor;
  320.               end;
  321.         end;
  322.         
  323.         procedure DrawTheTitle;
  324.         
  325.         begin
  326.             { find out how big the title is and center it in the control rectangle and draw the
  327.               it. this is NOT how the standard control does it.}
  328.             LineHeight:=theInfo.ascent+theInfo.Descent;
  329.             tempInt:=textRect.bottom-textRect.top;
  330.             if lineHeight<tempInt then
  331.               begin
  332.                 textRect.top:=textRect.top+((tempInt-lineHeight) div 2);
  333.                 textRect.Bottom:=textRect.top+LineHeight;
  334.               end;
  335.             if isSimpleButton then
  336.               begin
  337.                 tempInt:=StringWidth(theControl^^.contrlTitle);
  338.                 boxWidth:=textRect.right-textRect.left;
  339.                 if tempInt<boxWidth then
  340.                   begin
  341.                     TextRect.Left:=TextRect.left+((boxWidth-tempInt) div 2);
  342.                   end
  343.                 else
  344.                   TextRect.Left:=TextRect.Left;
  345.               end
  346.             else
  347.               textRect.Left:=textRect.Left+18;
  348.             textRect.Right:=textRect.left+stringWidth(theControl^^.contrlTitle);
  349.             MoveTo(textRect.left,textRect.top+theInfo.ascent);
  350.             DrawString(theControl^^.contrlTitle);
  351.         end;
  352.         
  353.         function ShrinkClip:boolean;
  354.         { Set the clip rgn of the grafport to be the intersection of the current clip rgn
  355.           and the control rectangle. This will insure that we never draw outside of out control
  356.           Return true if this results in an empty region. so that drawing does not take place }
  357.         var    Wally:boolean;
  358.         
  359.         begin
  360.             oldClipRgn:=NewRgn;
  361.             GetClip(oldClipRgn);    {copy the current clip region}
  362.             ClipRect(theControl^^.ContrlRect);
  363.             SectRgn(oldClipRgn,ThisWIndow^.ClipRgn,ThisWIndow^.clipRgn);
  364.             Wally:=EmptyRgn(ThisWindow^.ClipRgn);
  365.             if Wally then
  366.               begin
  367.                 SetClip(oldClipRgn);
  368.                 DisposeRgn(oldClipRgn);
  369.               end;
  370.             ShrinkClip:=Wally;
  371.         end;
  372.                   
  373.         procedure DrawIndBox;
  374.         
  375.         begin
  376.             {Draws the check box or little round radio button and fills it in. NOTE: the filled
  377.              in indicator is drawn in the frame color. With system 7, the indicator is never dimmed
  378.              and it is the only portion of the control that indicated a hilighted item CalcFrameColor
  379.              was called before this routine is called.}
  380.           CalcBackColor;
  381.           EraseRect(OuterRect);
  382.           if isHiLited then pensize(2,2);
  383.           if isCheckBox then FrameRect(OuterRect)
  384.           else FrameOval(outerRect);
  385.           penSize(1,1);
  386.           if theControl^^.contrlValue=0 then exit(DrawIndBox); {If value 0 then don't fill in indicator}
  387.           if isRadioBut then
  388.             begin
  389.               insetRect(outerRect,3,3);
  390.               PaintOval(outerRect);
  391.             end
  392.           else
  393.             begin
  394.               InsetRect(outerRect,1,1);
  395.               MoveTo(outerRect.left,outerRect.top);
  396.               LineTo(outerRect.right,outerRect.Bottom);
  397.               MoveTo(outerRect.right,outerRect.top-1);
  398.               Lineto(outerRect.left-1,outerRect.Bottom);
  399.             end;
  400.         end;
  401.         
  402.         Procedure DisableButton;
  403.         
  404.         begin
  405.             { if the useGrayText indicates that we have not already drawn the text in a
  406.               light gray fashion, then do the old style dimming on it.}
  407.             if UseGrayText then Exit(DisableButton);
  408.             if isSimpleButton then
  409.               begin
  410.                 CalcForeColor;
  411.                 CalcBackColor;
  412.               end;
  413.             InsetRect(CtlRect,1,1);
  414.             PenPat(QD.gray);
  415.             PenMode(patBIC);
  416.             if isSimpleButton then
  417.                PaintRoundRect(ctlRect,roundNess,roundNess)
  418.             else
  419.                PaintRect(textRect);
  420.         end;
  421.         
  422.     begin
  423.         if theControl^^.ContrlVis<>255 then exit(DoDrawIt); {no drawing needed for invisible controls}
  424.     { Set up some drawing variables that are used often for drawing }
  425.         ctlRect:=theControl^^.ContrlRect;
  426.         isDisabled:=(thisHiLite=255);
  427.         isNormal:=(thisHiLite=0);
  428.         isHiLited:=not(isDisabled or isNormal);
  429.         
  430.         if ShrinkClip then exit(DoDrawIt);
  431.         StdDrawSetup;
  432.         roundNess:=roundFactor;
  433.         { Erase the control bounding box }
  434.         if HasColorQD then CalcBackColor;
  435.         { if param=0 then }
  436.           EraseRoundRect(ctlRect,roundNess,roundNess);
  437.         outerRect:=ctlRect;
  438.         textRect:=outerRect;
  439.         if not(isSimpleButton) then
  440.           begin
  441.               tempInt:=(outerRect.bottom-OuterRect.top-12) div 2;
  442.             outerRect.Top:=outerRect.top+tempInt;
  443.             outerRect.Bottom:=outerRect.top+12;
  444.             outerRect.right:=outerRect.Left+12;
  445.           end;
  446.         CalcTextColor;
  447.         GetFontInfo(theInfo);
  448.         DrawtheTitle;
  449.         CalcFrameColor;
  450.         if IsSimpleButton then
  451.             FrameRoundRect(theControl^^.contrlRect,roundNess,roundNess)
  452.         else  DrawindBox;
  453.         if isDisabled then DisableButton;
  454.         { if we are on a black and white machine the button has yet to be inverted if
  455.           it is selected.}
  456.         if Not(HasColorQD) and isHiLited then
  457.           InvertRoundRect(ctlRect,roundNess,roundNess);
  458.         SetClip(oldClipRgn);
  459.         DisposeRgn(oldClipRgn);
  460.         StdDrawTearDown;
  461.     end;
  462.     
  463. Begin
  464.     theResult:=0;
  465.     ResultValid:=false;
  466.     thisCDPInfo:=cdpInfo(theControl^^.ContrlDefProc);
  467.     thisWindow:=theControl^^.contrlOwner;
  468.     thisHiLite:=theControl^^.ContrlHiLite;
  469.     isSimpleButton:= thisCDPInfo[0]=0;
  470.     isCheckBox:= thisCDPInfo[0]=1;
  471.     isRadioBut:= thisCDPInfo[0]=2;
  472.     Case Message of
  473.         drawCntl    : DoDrawIt;
  474.         testCntl    : DoTestCntl;
  475.         calcCRgns    : DoCalcCRegions;
  476.         initCntl     : ;        { can be used to initialize special control data structures }
  477.         dispCntl    : ;        { If you need to clean up anything before you finish }
  478.         posCntl     : ;        { If you don't want standard control mgr moveing }
  479.         thumbCntl     : ;        { for use with custom thumb dragging routines }
  480.         dragCntl     : ;        { for custom dragging of the control, or parts of }
  481.         autoTrack     : ;        { a default track control function for all controls of this type }
  482.         calcCntlRgn,
  483.         calcThumbRgn: begin
  484.                            ResultValid:=true;
  485.                         theResult:=1;
  486.                         DoCalcCRegions;
  487.                       end;
  488.       Otherwise ;
  489.     end; {Case}
  490.     If ResultValid then MySampControl:=theResult
  491.       else MySampControl:=0;
  492. End;
  493.  
  494. End.
  495.